; (function (factory) {
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        factory(require('jquery'));
    } else {
        factory(jQuery);
    }
}(function ($) {
    $.fn.select = function (options) {
        var defaults = {
            'data': {},
            'url': '',
            'parentID': 'parent_id',
            'rootID': 0,
            'name': 'name',
            'selected': null,
            'selectedIcon': "fa-check",
            'openIcon': 'fa-folder-open',
            'closeIcon': 'fa-folder',
            'nodeIcon': 'fa-file',
            'extendAllIcon': 'fa-folder-open-o',
            'collectAllIcon': 'fa-folder-o',
            'clickSpan': null,
            'multiple': 'false',
            'lang': {
                'extendAll': '展开全部',
                'collectAll': '收起全部',
                'placeholder': '请选择...',
                'search': '搜索...',
                'clear': '清除所选',
                'refresh': '重置搜索'
            },
            'deep': 4
        };

        var self = this;
        var $this = $(this);

        this.settings = $.extend(defaults, options);

        this.settings.multiple = $this.attr('multiple') ? true : false;

        var _init = function () {
            var $id = (((1 + Math.random()) * 0x100001000) | 0).toString(16).substring(0);
            create($id);
            $("a i." + self.settings.openIcon + ",a i." + self.settings.closeIcon + ",a span")
                .css('cursor', 'hand')
                .css('cursor', 'pointer');

            if (self.settings.multiple == false) {
                $.isArray(self.settings.selected) ?
                    $this.val(self.settings.selected[0])
                    : $this.val(self.settings.selected)
            } else {
                $this.val(self.settings.selected);
            }
            
            bind();
        }

        var create = function ($id) {
            $('<div>', { class: "btn-group", width: "100%", id: "st_" + $id })
                .append('<div class="form-control dropdown-toggle" data-toggle="dropdown">' +
                    '<span id="_selected"></span>' +
                    '<span class="fa fa-sort-desc form-control-feedback" style="margin-top:7px;"></span></div>' +
                    '<ul class="dropdown-menu" style="min-width:300px;width:100%">' +
                    '<div style="margin:0 5px;"><div class="input-group">' +
                    '<input type="text" class="form-control searchText" placeholder="' + self.settings.lang.search + '">' +
                    '<span class="input-group-btn">' +
                    '<button class="btn btn-default refresh" type="button" title="' + self.settings.lang.refresh + '"><i class="fa fa-refresh"></i></button>' +
                    '<button class="btn btn-default clearSelected" type="button" title="' + self.settings.lang.clear + '"><i class="fa fa-trash"></i></button>' +
                    '<button class="btn btn-default extendAll" type="button" title="' + self.settings.lang.collectAll + '"><i class="fa ' + self.settings.extendAllIcon + '"></i></button>' +
                    '</span>' +
                    '</div></div><div class="jtree" id="' + self.settings.rootID + '"></div></ul>'
                ).insertBefore($this.addClass('hidden'));


            if (self.settings.data.length != 0) {
                $.each(self.settings.data, function (key, val) {
                    var value = val.value ? val.value : val.id;
                    $this.append($("<option>", { 'value': value })
                        .data('id', val.id)
                        .data('parent', val[self.settings.parentID])
                        .data('open', val.open ? true : false)
                        .html(val[self.settings.name]));
                });
            }
            if (self.settings.url != null) {
            }
            var datas = [];
            $this.find('option').each(function () {
                datas.push({
                    'id': $(this).data('id') ? $(this).data('id') : $(this).attr("value"),
                    'parent': $(this).data('parent') ? $(this).data('parent') : self.settings.rootID,
                    'open': $(this).data('open') ? true : false,
                    'value': $(this).attr("value") ? $(this).attr("value") : $(this).data('id'),
                    'name': $(this).html()
                });
            });
            _buildTree(datas);
        }
        var _buildTree = function (data) {
            var nofind = [];
            for (var node in data) {
                //find parent node
                var parentNode = $this.prev().find('#' + data[node]['parent']);
                //finded
                if (parentNode.length != 0) {
                    //node setted value?
                    var value = data[node]['value'] ? data[node]['value'] : data[node]['id'];
                    var checkbox = self.settings.multiple == false ?
                        "<input type='radio' name='selectTree' value='" + value + "' id='t_" + data[node]["id"] + "'/>" :
                        "<input type='checkbox' name='selectTree' value='" + value + "' id='t_" + data[node]["id"] + "'/>";
                    // create node html
                    var nodeHtml = $('<li>', {
                        'id': data[node]['id'],
                        'class': 'dropdown-item'
                    }).data("open", data[node]["open"])
                        .data("parent", data[node]["parent"])
                        .data("value", value)
                        .data("name", data[node]["name"])
                        .data("id", data[node]["id"])
                        .append('<a class="nodeName">' +
                            checkbox + ' <i class="fa ' + self.settings.nodeIcon + '"></i>' +
                            '<span>' + data[node]['name'] + '</span>' +
                            '</a></li>');
                    // parent has ul?
                    if (parentNode.find('ul').length == 0) {
                        parentNode.append($('<ul>'));
                        parentNode.children('a').children('i').removeClass(self.settings.nodeIcon).addClass(self.settings.openIcon);
                        if (data[node]['parent'] != self.settings.rootID && parentNode.data("open") == false) {
                            parentNode.children('a').children('i').removeClass(self.settings.openIcon).addClass(self.settings.closeIcon);
                            parentNode.children('ul').hide();
                        }
                    }
                    //node is selected
                    var isSelected = $.isArray(self.settings.selected) ?
                        ($.inArray(data[node]['id'].toString(), self.settings.selected) != -1)
                        : (data[node]['id'].toString() == self.settings.selected);

                    if (isSelected) {
                        nodeHtml.find("a input").attr("checked", true);
                        self.settings.multiple == true ?
                            $this.prev().find("#_selected").append(_selectedBtn(data[node]))
                            : $this.prev().find('#_selected').html(_selectedBtn(data[node]));
                    }
                    //node append into parent
                    parentNode.children('ul').append(nodeHtml);
                } else { // no find parent
                    nofind.push(data[node]);
                }
            }
            if (nofind.length != 0 && self.settings.deep >= 0) {
                _buildTree(nofind);
                self.settings.deep--;
            }
        }
        var _selectedBtn = function (option) {
            return '<button class="btn btn-default btn-xs" style="margin-right:5px;" type="button" data-selected="' + option.id + '">' +
                option.name
                + '<span class="fa fa-close"></span></button>';
        }
        var _findBtn = function ($div, id) {
            return $div.find('#_selected').find("[data-selected=" + id + "]").length;
        }
        var _removeBtn = function ($div, id) {
            $div.find('#_selected').find("[data-selected=" + id + "]").remove();
            $div.find("#t_" + id + ":first").prop("checked", false).removeAttr("checked");
            $this.trigger("change.selected");
        }
        var _removeAll = function ($div) {
            $div.find('#_selected').find("[data-selected]").each(function () {
                _removeBtn($div, $(this).data("selected"));
            });
            $this.val('');
            $this.trigger("change.selected");
        }
        var _getChild = function (id) {
            var child;
            $.ajax({
                url: settings.url,
                type: 'get',
                dataType: 'json',
                async: false,
                data: {
                    pid: id
                },
                success: function (data) {
                    child = data;
                }
            });
            return child;
        }
        var _click = function (span, $div) {
            var option = span.parents("li:first").data();

            if (self.settings.multiple) {
                if (span.prop("checked")) {
                    $div.find('#_selected').append(_selectedBtn(option));
                    span.prop("checked", true);
                } else {
                    _removeBtn($div, option.id);
                    span.removeAttr("checked");
                }
            } else {
                span.prop("checked", true);
                $div.find('#_selected').html(_selectedBtn(option));
            }
            $this.trigger("change.selected");
        };
        var extendAll = function ($div) {
            $div.find("#" + self.settings.rootID).children("ul").find('ul').slideDown("fast");
            $div.find("#" + self.settings.rootID).find("i").removeClass(self.settings.closeIcon).addClass(self.settings.openIcon);
        }
        var collectAll = function ($div) {
            $div.find("#" + self.settings.rootID).children("ul").find('ul').slideUp("fast");
            $div.find("#" + self.settings.rootID).find("i").removeClass(self.settings.openIcon).addClass(self.settings.closeIcon);
        }
        var bind = function () {
            var $div = $this.prev();
            $this.on("change.selected", function () {
                var value;
                if (self.settings.multiple) {
                    value = [];
                    $div.find(":checked").each(function () {
                        $(this).prop("checked") ?
                            value.push($(this).val())
                            : ""
                    })
                } else {
                    value= $div.find(":checked").val();
                }
                $this.val(value);
            });
            $div.find(' .dropdown-menu button,a i').click(function (e) {
                e.stopPropagation();
            });
            if (self.settings.multiple == true) {
                $div.find('.dropdown-menu a').click(function (e) {
                    e.stopPropagation();
                });
            }
            $div.find(' a i.' + self.settings.openIcon + ", a i." + self.settings.closeIcon).click(function () {
                var li = $(this).parent("a").parent("li");
                li.children("ul").slideToggle("fast");
                $(this).toggleClass(self.settings.openIcon + " " + self.settings.closeIcon);
            });
            $div.find('button.extendAll').click(function () {
                if ($(this).children('i').hasClass(self.settings.collectAllIcon)) {
                    extendAll($div);
                    $(this).attr("title", self.settings.lang.collectAll);
                } else {
                    collectAll($div);
                    $(this).attr("title", self.settings.lang.extendAll);
                }
                $(this).children('i').toggleClass(self.settings.extendAllIcon + " " + self.settings.collectAllIcon);
            });
            $div.find('input.searchText').keyup(function () {
                var search = $(this).val();
                extendAll($div);
                $div.find('li').hide().filter(":contains('" + search + "')").show();
            });
            $div.find("button.refresh").click(function () {
                $(this).parent().prev("input.searchText").val("").keyup();
            });
            $div.find('a input').click(function () {
                _click($(this), $div);
            });
            $div.find('a span').click(function (e) {
                e.preventDefault();
                if ($.isFunction(self.settings.check)) {
                    self.settings.clickSpan($(this));
                } else {
                    $(this).prev().prev("input").click();
                }
            });
            $div.on("click", "[data-selected]", function (e) {
                var id = $(this).data("selected");
                _removeBtn($div, id);
                if (self.settings.multiple) {
                    var value = [];
                    $(":checked").each(function () {
                        $(this).prop("checked") ?
                            value.push($(this).val())
                            : ""
                    })
                    $this.val(value)
                } else {
                    $this.val('')
                }
            });
            //clear all selected
            $div.find('button.clearSelected').click(function () {
                _removeAll($div);
            });
        };
        this.value = function () {
            return $(this).val()
        }
        _init();
        return this;
    }
}));